
import collections
import itertools
import copy
# 字牌 带顺

# 分 风牌 和 箭牌
# 再合起来

base_feng_tb = [
    [0,0,0,0],
    [0,1,1,1],
    [1,0,1,1],
    [1,1,0,1],
    [1,1,1,0],
    [3,0,0,0],
    [0,3,0,0],
    [0,0,3,0],
    [0,0,0,3]
]

base_jian_tb = [
    [0,0,0],
    [1,1,1],
    [3,0,0],
    [0,3,0],
    [0,0,3]
]

baida_table = collections.OrderedDict()
baida_eye_table = collections.OrderedDict()

for i in range(0,5):
    baida_table.setdefault(i,{})
    baida_eye_table.setdefault(i,{})

zi_bai_da_with_shun_table = collections.OrderedDict()
eye_zi_bai_da_with_shun_table = collections.OrderedDict()
for i in range(0,5):
    zi_bai_da_with_shun_table.setdefault(i,{})
    eye_zi_bai_da_with_shun_table.setdefault(i,{})


def perm(list1):
    list2 = []
    for i in range(0,len(list1)):
        iter = itertools.combinations_with_replacement(list1,i)
        for j in iter:
            if list(j) not in list2:
                list2.append(list(j))
    return list2

def get_feng_combo_list():
    feng_list = perm(range(0, 9))
    feng_combo_list = []
    feng_use_three = {} #[key] -> 0

    for feng in feng_list:
        tmp_feng_list = [0, 0, 0, 0]
        tmp_feng = copy.deepcopy(feng)
        tIndex = 0
        while tIndex != len(tmp_feng):
            if tmp_feng[tIndex] == 0:
                del tmp_feng[tIndex]
            else:
                tIndex += 1

        use_len = len(tmp_feng)
        if use_len > 4:
            continue
        flag = True
        for data in feng:
            for i in range(0, 4):
                tmp_feng_list[i] += base_feng_tb[data][i]
                if tmp_feng_list[i] > 6:
                    flag = False
                    break
        if flag:
            copy_tmp_feng_list = copy.deepcopy(tmp_feng_list)
            for index, data in enumerate(copy_tmp_feng_list):
                copy_tmp_feng_list[index] = str(data)
            key_str = ''.join(copy_tmp_feng_list)
            if tmp_feng_list not in feng_combo_list:
                feng_use_three.setdefault(key_str, [])
                feng_combo_list.append(tmp_feng_list)
            if use_len not in feng_use_three[key_str]:
                feng_use_three[key_str].append(use_len)

    print(feng_use_three)
    return feng_combo_list,feng_use_three

def get_jian_combo_list():
    jian_list = perm(range(0, 5))
    jian_use_three = {} # 0 -> [key]

    for jian in jian_list:
        tmp_jian_list = [0, 0, 0]

        tmp_jian = copy.deepcopy(jian)
        tIndex = 0
        while tIndex != len(tmp_jian):
            if tmp_jian[tIndex] == 0:
                del tmp_jian[tIndex]
            else:
                tIndex += 1

        use_len = len(tmp_jian)
        if use_len > 4:
            continue
        flag = True
        for data in jian:
            for i in range(0, 3):
                tmp_jian_list[i] += base_jian_tb[data][i]
                if tmp_jian_list[i] > 6:
                    flag = False
                    break
        if flag:
            if use_len not in jian_use_three:
                jian_use_three.setdefault(use_len, [])

            if tmp_jian_list not in jian_use_three[use_len]:
                jian_use_three[use_len].append(tmp_jian_list)

    return jian_use_three


def get_zi_with_shun_table():
    feng_combo_list,feng_use_three = get_feng_combo_list()
    jian_use_three = get_jian_combo_list()

    copy_feng_combo_list = copy.deepcopy(feng_combo_list)
    for index, data in enumerate(copy_feng_combo_list):
        for i,d in enumerate(data):
            copy_feng_combo_list[index][i] = str(d)

    zi_combo_list = []
    for index,data in enumerate(copy_feng_combo_list):
        key_str = ''.join(data)
        left_list = feng_use_three[key_str]
        for left in left_list:
            left_num = 4 - left
            for num in range(0,left_num + 1):
                for jian_list in jian_use_three[num]:
                    tmp_zi_combo_list = copy.deepcopy(feng_combo_list[index])
                    tmp_zi_combo_list.extend(jian_list)
                    zi_combo_list.append(tmp_zi_combo_list)
    return zi_combo_list

def gen_eye_zi_with_shun_table():

    zi_combo_list = get_zi_with_shun_table()
    zi_eye_combo_list = []
    value_list = []

    for zi_list in zi_combo_list:
        for i in range(0, 7):
            tmp_eye_combo_list = copy.deepcopy(zi_list)
            if zi_list[i] > 2:
                continue
            tmp_eye_combo_list[i] += 2
            value_list.append(1 + ((i + 1) << 4) + (0 << 8))
            zi_eye_combo_list.append(tmp_eye_combo_list)

    return zi_eye_combo_list,value_list

def add(key,baida_num,eye,value):
    if eye == False:
        if key not in zi_bai_da_with_shun_table[baida_num]:
            zi_bai_da_with_shun_table[baida_num].setdefault(key, [])
        zi_bai_da_with_shun_table[baida_num][key] = value[0]
    else:
        if key not in eye_zi_bai_da_with_shun_table[baida_num]:
            eye_zi_bai_da_with_shun_table[baida_num].setdefault(key, [])
        eye_zi_bai_da_with_shun_table[baida_num][key] = value[0]


def check_add(e_list,baida_num,eye,value):
    key_num = 0
    for i in range(0,7):
        key_num = key_num * 10 + e_list[i]

    nor_table = {}

    if eye == False:
        nor_table = baida_table[baida_num]
    else:
        nor_table = baida_eye_table[baida_num]

    if key_num in nor_table:
        return False

    nor_table.setdefault(key_num, True)

    for i in range(0, 7):
        if e_list[i] > 4:
            return True

    tmp_value = copy.deepcopy(value)
    maxBaiDaCard = 0
    for i in range(0, 4):
        baiDaCard = (tmp_value[0] >> (12 + i * 4)) & 0xF
        if baiDaCard > maxBaiDaCard:
            maxBaiDaCard = baiDaCard

    tmp_value[0] |= (maxBaiDaCard << 8)

    add(key_num,baida_num,eye,tmp_value)
    return True

def get_last_key_value(cards,baida_num,eye):
    key = 0
    for i in range(0,7):
        key = key * 10 + cards[i]

    if key == 0:
        return False,0

    if eye == True:
        if key in eye_zi_bai_da_with_shun_table[baida_num]:
            return True,eye_zi_bai_da_with_shun_table[baida_num][key]
        else:
            return False,0
    else:
        if key in zi_bai_da_with_shun_table[baida_num]:
            return True,zi_bai_da_with_shun_table[baida_num][key]
        else:
            return False,0

def add_not_first_time(cards,baida_num,eye,value):
    key = 0
    for i in range(0, 7):
        key = key * 10 + cards[i]

    nor_table = {}

    if eye == False:
        nor_table = baida_table[baida_num]
    else:
        nor_table = baida_eye_table[baida_num]

    for i in range(0,7):
        if cards[i] > 4:
            return True

    add(key,baida_num,eye,value)
    return True

def parse_table_sub(cards,baida_num,eye,value,value_count):
    tmp_value = copy.deepcopy(value)
    tmp_value_count = copy.deepcopy(value_count)
    for i in range(0,7):
        if cards[i] == 0:
            continue

        cards[i] -= 1
        tmp_value[0] |= (i + 1) << value_count[0]
        tmp_value_count[0] += 4

        if not check_add(cards,baida_num,eye,tmp_value):
            flag, last_value = get_last_key_value(cards, baida_num, eye)
            if flag == True:
                tt_value = copy.deepcopy(tmp_value)
                maxBaiDaCard = 0
                for j in range(0, 4):
                    baiDaCard = (tt_value[0] >> (12 + j * 4)) & 0xF
                    if baiDaCard > maxBaiDaCard:
                        maxBaiDaCard = baiDaCard

                tt_value[0] |= (maxBaiDaCard << 8)
                last_max_value = last_value >> 8 & 0xF
                max_value = tt_value[0] >> 8 & 0xF
                if max_value > last_max_value:
                    add_not_first_time(cards, baida_num, eye, tt_value)
            cards[i] += 1
            tmp_value = copy.deepcopy(value)
            tmp_value_count = copy.deepcopy(value_count)
            continue

        if baida_num < 4:
            parse_table_sub(cards,baida_num + 1,eye,tmp_value,tmp_value_count)

        cards[i] += 1
        tmp_value = copy.deepcopy(value)
        tmp_value_count = copy.deepcopy(value_count)

def parse_table(cards,eye,value,value_count):
    if not check_add(cards,0,eye,value):
        return
    parse_table_sub(cards,1,eye,value,value_count)

def gen_zi_bai_da_with_shun_table():
    zi_combo_list = get_zi_with_shun_table()
    value = [0]
    value_count = [12]
    tmp_value = copy.deepcopy(value)
    tmp_value_count = copy.deepcopy(value_count)
    for table in zi_combo_list:
        parse_table(table,False,tmp_value,tmp_value_count)
        tmp_value = copy.deepcopy(value)
        tmp_value_count = copy.deepcopy(value_count)

def gen_eye_zi_bai_da_with_shun_table():
    eye_zi_combo_list,value_list = gen_eye_zi_with_shun_table()
    value_count = [12]
    tmp_value_count = copy.deepcopy(value_count)
    for index,table in enumerate(eye_zi_combo_list):
        value = [value_list[index]]
        parse_table(table,True,value,tmp_value_count)
        tmp_value_count = copy.deepcopy(value_count)


# gen_zi_bai_da_with_shun_table()
# gen_eye_zi_bai_da_with_shun_table()
#
# for i in range(0,5):
#     with open("E:\PythonWorkSpace\generate_list_hu\\tables\\baida_zi_with_shun_table" + str(i) + ".txt","w") as file:
#         for s in zi_bai_da_with_shun_table[i]:
#             # ss = "baiDaZiWithShunTable[{index}].insert(std::pair<uint32_t,bool>({key},true));".format(index = i,key = s)
#             ss = "{key},{value}".format(key = s,value=zi_bai_da_with_shun_table[i][s])
#             file.writelines(ss + "\n")
#
# for i in range(0,5):
#     with open("E:\PythonWorkSpace\generate_list_hu\\tables\\baida_eye_zi_with_shun_table" + str(i) +".txt","w") as file:
#         for s in eye_zi_bai_da_with_shun_table[i]:
#             # ss = "baidaEyeZiWithShunTable[{index}].insert(std::pair<uint32_t,bool>({key},true));".format(index = i,key = s)
#             ss = "{key},{value}".format(key=s,value=eye_zi_bai_da_with_shun_table[i][s])
#             file.writelines(ss + "\n")